package org.melanesia.beans.validation;

import org.melanesia.conf.exceptions.ConfigurationException;

/**
 * Helper class holding property validation metadata. Instances of this class
 * are being constructed in two places:
 *
 * <ol>
 * <li>inside {@link org.melanesia.conf.Config} when bean validation setup is
 * loaded from config file</li>
 * <li>inside {@link org.melanesia.beans.validation.BeanValidator} when bean
 * validation setup is determined using reflection</li>
 * </ol>
 *
 * The constructed {@code PropertyValidationData} objects are then used to pass
 * into validation methods and to store in cache, for further use.
 *
 * @author marcin.kielar
 */
public class PropertyValidationData {

    /** @see org.melanesia.beans.validation.ValidationRules#nullable() */
    private final boolean nullable;

    /** @see org.melanesia.beans.validation.ValidationRules#validator() */
    private final Validator validator;

    /**
     * Constructs new {@code PropertyValidationData} from parameters given by
     * hand (this method is used when parsing configuration file).
     *
     * @param nullable
     *            whether to populate property for null values
     * @param validatorClassName
     *            optional custom validator
     */
    public PropertyValidationData(final Boolean nullable, final String validatorClassName) {
        try {
            this.nullable = nullable == null || nullable;
            if (validatorClassName != null && !"".equals(validatorClassName.trim())) {
                this.validator = (Validator) Class.forName(validatorClassName).newInstance();
            } else {
                this.validator = null;
            }
        } catch (Throwable t) {
            throw new ConfigurationException("Error during property validation configuration.", t);
        }
    }

    /**
     * Constructs new {@code PropertyValidationData} from parameters given in
     * property annotation. This method is used during reflection analysis.
     *
     * @param annotation
     *            annotation with validation metadata
     */
    public PropertyValidationData(final ValidationRules annotation) {
        try {
            this.nullable = Boolean.TRUE.equals(annotation.nullable());
            if (annotation.validator() != null && annotation.validator() != Validator.class) {
                this.validator = annotation.validator().newInstance();
            } else {
                this.validator = null;
            }
        } catch (Throwable t) {
            throw new ConfigurationException("Error during property validation configuration.", t);
        }
    }

    /**
     * @see org.melanesia.beans.validation.ValidationRules#nullable()
     * @return whether to validate property for null values
     */
    public final boolean isNullable() {
        return nullable;
    }

    /**
     * @see org.melanesia.beans.validation.ValidationRules#validator()
     * @return custom validator
     */
    public final Validator getValidator() {
        return validator;
    }
}